package com.young.javasist

import com.android.build.api.transform.*
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.internal.pipeline.TransformManager
import javassist.ClassPool
import javassist.CtClass
import javassist.CtMethod
import javassist.CtNewMethod
import org.apache.commons.io.FileUtils
import org.gradle.api.Project

public class ModifyTransform extends Transform {

    Project mProject
//    内存   windown   1  android 2
    ClassPool pool = ClassPool.default

    ModifyTransform(Project project) {
        mProject = project
    }

    @Override
    String getName() {
        return "young"
    }

    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() {
        return false
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        super.transform(transformInvocation)
        BaseExtension android = mProject.getExtensions().findByType(BaseExtension.class)
        android.bootClasspath.each {
            pool.appendClassPath(it.absolutePath)
        }

        //       1 拿到输入
        transformInvocation.inputs.each { transformInput ->

            transformInput.directoryInputs.each { directoryInput ->
                // 目录路径
                def dirPath = directoryInput.file.absolutePath
                pool.insertClassPath(dirPath)
//                println("类的文件输入路径： " + dirPath)
                // 找到目标文件
                findTarget(directoryInput.file, dirPath)

                // 2 查询输出的文件夹    目的地
                def dest = transformInvocation.outputProvider
                        .getContentLocation(directoryInput.name, directoryInput.contentTypes, directoryInput.scopes, Format.DIRECTORY)
//                println("类的文件夹输出路径： " + dest)
                // 3  文件copy  ---》 下一个环节
                FileUtils.copyDirectory(directoryInput.file, dest)
            }

            // 复制 jar 包
            transformInput.jarInputs.each { jarInput ->

//                println("jar的文件输入路径： " + jarInput.file.absolutePath)

                // jar 包的输出路径
                def dest = transformInvocation.outputProvider.getContentLocation(
                        jarInput.name,
                        jarInput.contentTypes,
                        jarInput.scopes,
                        Format.JAR
                )

//                println("jar的文件输出路径： " + dest)

                // 复制jar包
                FileUtils.copyFile(jarInput.file, dest)
            }

        }

    }

    /**
     * 找到目标文件
     * @param dir 文件目录
     * @param parentDirPath 父级目录路径
     */
    private void findTarget(File dir, String parentDirPath) {
        if (dir.isDirectory()) {
            dir.listFiles().each {
                findTarget(it, parentDirPath)
            }
        } else {
            def filePath = dir.absolutePath
            if (filePath.endsWith(".class")) {
//                println("目标文件 " + filePath)
                modify(filePath, parentDirPath)
            } else {
//                println("非目标文件 " + filePath)
            }
        }
    }

    /**
     * 修改文件
     * @param filePath 文件路径
     * @param parentDirPath
     */
    private void modify(def filePath, String parentDirPath) {
        if (filePath.contains('R$') || filePath.contains('R.class')
                || filePath.contains("BuildConfig.class")) {
            return
        }
        println("目标文件 " + filePath)
        println("目标文件 " + parentDirPath)

        // 基于javassit  ----》
        def className = filePath.replace(parentDirPath, "").replace("\\", ".").replace("/", ".")
        def name = className.replace(".class", "").substring(1)
        println("name = " + name)

        //        json 文件   ----》 javabean-- 修改---》 fastjson ----》回写到  json文件
        CtClass ctClass = pool.get(name)
////        CtClass ctClass=  pool.getAndRename(name,name+"1")
////        addCode(ctClass, parentDirPath)
////        ctClass.setName(name+"1")
////        ctClass.setName("com.young.tiankong.MainActivity")
////        ctClass.replaceClassName(name,"com.young.tiankong.MainActivity")
////        ctClass.replaceClassName(name,name+"2")
//        def fil = ctClass.getClassFile()
//        fil.renameClass(name, name + "2")
//        ctClass.writeFile(parentDirPath)
//        ctClass.detach()
        addCode(ctClass, parentDirPath)
    }

    private void addCode(CtClass ctClass, String fileName) {
//        捡出来
        ctClass.defrost()
        CtMethod[] methods = ctClass.getDeclaredMethods()
        for (method in methods) {

            if (ctClass.getName().contains("LogUtil") && method.name.contains("logE")) {
                // 添加一个方法
                CtMethod method1 = CtNewMethod.make("public void newMethod() { System.out.println(\"New method executed\"); }",ctClass)
                ctClass.addMethod(method1)
            }

            println "method " + method.getName() + "参数个数  " + method.getParameterTypes().length
            method.insertAfter("if(true){}")
            if (method.getParameterTypes().length == 1) {
                method.insertBefore("{ System.out.println(\$1);}")
            }
            if (method.getParameterTypes().length == 2) {
                method.insertBefore("{ System.out.println(\$1); System.out.println(\$2);}")
            }
            if (method.getParameterTypes().length == 3) {
                method.insertBefore("{ System.out.println(\$1);System.out.println(\$2);System.out.println(\\\$3);}")
            }

            if (ctClass.getName().contains("LogUtil") && method.name.contains("logE")) {
                method.setBody("newMethod();")
            }

        }

        ctClass.writeFile(fileName)
        ctClass.detach()
    }
}